package helper;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import rayTracer.ImagePlate;
import rayTracer.Pixel;
import static rayTracer.ApplicationInterface.*;


public class Util {
	
	// Crea un vector a partir de 2 puntos: vec = p2 - p1
	public static Vector3d getVector(Point3d p1, Point3d p2) {
		Point3d aux = new Point3d();
		aux.sub(p2, p1);
		return new Vector3d(aux);
	}
	
	// Calcula el vector normal a los 2 vectores pasados como argumentos
	public static Vector3d getVecNormal(Vector3d v1, Vector3d v2) {
		Vector3d vecNormal = new Vector3d();
		vecNormal.cross(v1, v2);
		return vecNormal;
	}
	
	// Calcula la direccion del vector reflejado respecto de una direccion normal
	public static Vector3d getReflectedDir(Vector3d vec, Vector3d normal) {
		// R = 2*(N dot V)*N - V
		Vector3d reflected = new Vector3d();
		double dot = normal.dot(vec);
		reflected.scale(2*dot, normal);
		reflected.sub(vec);
		return reflected;
	}
	
	// Multiplica 2 arreglos componente a componente, luego los multiplica por
	// una constante y acumula el resultado en otro arreglo
	public static void prodAcumRGBComponents(float acum[], double k, float a1[], float a2[]) {
		for( int i=1; i < 4; i++ ) {
			acum[i] += k*a1[i]*a2[i];
		}
	}

	// Multiplica un arreglo por una constante y acumula el resultado en otro arreglo
	public static void scaleAcumRGBComponents(float acum[], double k, float a[]) {
		for( int i=1; i < 4; i++ ) {
			acum[i] += k*a[i];
		}
	}

	// Muestra el contenido de los arreglos de puntos
	public static String show(Point3d[] pts) {
		String s = "[";
		int i;
		for( i=0; i < pts.length-1; i++ ) {
			s += pts[i].toString() + ", ";
		}
		s += pts[i].toString() + "]";
		return s;
	}
	
	/*
	 * Saves the pixels in an array to a file indicated by outputFile parameter
	 * It also allows you to choose the format: "png" and "bmp" are the only
	 * formats supported at this time. 
	 */
	public static boolean saveImage( Pixel[] pixelsArray, int width, int height, String outputFile, String format ) {
		String formatChoosen = "bmp";
		BufferedImage buffImage = null;
		String output = null;
		int len = pixelsArray.length;
		int requiredLen = width*height;
		
		if( len > requiredLen ){
			System.out.println("Pixels array is larger than the image dimensions. " + "Array = " + len + ", Image = " + requiredLen);
			return false;
		}
		if( format.compareToIgnoreCase("png") == 0 ){
			//We create a BufferedImage that supports RGB with transparency
			buffImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
			formatChoosen = "png";
		}else if( format.compareToIgnoreCase("bmp") == 0 ){
			//BMP format does not support transparency
			buffImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		}else{
			System.out.println("Format not supported !!");
			return false;
		}		
		
		//Calculate the position in the image matrix from the pixels array
		//and set the RGB value to the Buffered image
		for( int i=0 ; i<pixelsArray.length ; i++ ){
			int x = i%width;
			int y = (i - x)/width;
			buffImage.setRGB(x, y, pixelsArray[i].getPixel());
		}
		
		if( outputFile == null || outputFile.compareTo("") == 0)
			output = OUT_FILE;
		else
			output =  outputFile;
		
		File fout = new File("img/" + output +"." + formatChoosen);
	    try {
			ImageIO.write(buffImage, formatChoosen, fout);
		} catch (IOException e) {
			e.printStackTrace();
		}		return true; 
	}
	
	/*
	 * Saves pixel information in a plate to a file indicated by the outputFIle
	 * parameter.
	 * Formats supported at this time: "png" and "bmp"
	 * The dimensions of the image to be saved, are the ones defined in the
	 * plate Object 
	 */
	public static boolean saveImage( ImagePlate plate, String outputFile, String format ){
		//int width = plate.getWidth();
		//int height = plate.getHeight();		
		Pixel[] arr = plate.getPixelsArray();
		return saveImage(arr, plate.width, plate.height, outputFile, format);		
	}
	
}
